package com.wefans.wefansapp.common.tool.network;

import java.util.Hashtable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import android.content.Context;
import android.os.Handler;
import android.os.Looper;

import com.wefans.wefansapp.common.tool.data.MFDataManager;
import com.wefans.wefansapp.common.tool.data.UrlInfo;
import com.wefans.wefansapp.common.tool.debug.MFDebug;
import com.wefans.wefansapp.common.tool.finals.FEATURES;
import com.wefans.wefansapp.common.tool.network.engine.MFNetwork;
import com.wefans.wefansapp.common.tool.network.model.NetImage;
import com.wefans.wefansapp.common.tool.network.model.NetJsonData;
import com.wefans.wefansapp.common.tool.network.model.NetMessage;
import com.wefans.wefansapp.common.tool.network.model.NetUploadMessage;

/**
 * Network Manager 클래스
 * 
 * <pre>
 * [예제]
 * MFNetworkManager netMgr = MFNetworkManager.getInstane(getActivity());
 * netMgr.requestImageData(currentTimeMillis(), String url, this);
 * ...
 * public void onNetMessage(int resultCode, NetMessage message)
 * {
 *     if( message instanceof NetImage ) {
 *         //요청한 이미지 데이터 처리
 *     }
 *     else {
 *         //서버 응답 메시지 처리
 *     }
 * }
 * </pre>
 * 
 * @author kimhyeongbae
 */
public class MFNetworkManager
{
    //////////////////////////////////////////////////////////////////////////////////////
    // final/static property
    //////////////////////////////////////////////////////////////////////////////////////
    public static final String BASE_URL  = "http://api.wefansapp.com";
    public static final String API_KEY   = "MAMAafklh363KLahkl2";
    
    public static long REQUEST_BENEFIT 				= 1000;
    public static long REQUEST_BENEFIT_DETAIL		= 1001;
    public static long REQUEST_BENEFIT_RESULT		= 1002;
    public static long REQUEST_BENEFIT_USER			= 1003;
    public static long REQUEST_BENEFIT_VOTE			= 1004;
    
    public static long REQUEST_GET_USER 			= 2000;//P17  : 나의 정보
    public static long REQUEST_GET_VOTE             = 2001;//p24  : 투표 리스트
    public static long REQUEST_GET_COUNTRY          = 2002;//2.48 : 국가 정보
    public static long REQUEST_GET_APP_VERSION      = 2003;//2.47 : 어플 업데이트 정보 확인
    public static long REQUEST_GET_VOTE_ONE         = 2004;//p25  : 투표 상세
    public static long REQUEST_SET_VOTE             = 2005;//p27  : 투표하기
    public static long REQUEST_REPLY_LIST         	= 2006;
    public static long REQUEST_REPLY_REGIST        	= 2006;
    public static long REQUEST_REPLY_DEL         	= 2007;
    public static long REQUEST_REPLY_REPORT        	= 2008;
    
    public static long REQUEST_CHECK_EMAIL 			= 3001;
    public static long REQUEST_CHECK_NICKNAME 		= 3002;
    public static long REQUEST_CHECK_RECOMMENDER	= 3003;
    public static long REQUEST_TERMS				= 3004;
    public static long REQUEST_LOGIN				= 3005;
    public static long REQUEST_FIND_ID				= 3006;
    public static long REQUEST_FIND_ALLID			= 3007;
    public static long REQUEST_TEMP_PASSWORD		= 3008;
    public static long REQUEST_ALLSTAR_INFO 		= 3009;
    public static long REQUEST_LOGIN_WEIBO			= 3010;
    public static long REQUEST_LOGIN_WECHAT			= 3011;
    public static long REQUEST_CHANGE_PASSWORD		= 3012;
    public static long REQUEST_EXIT_MEMBER			= 3013;
    public static long REQUEST_DELETE_PHOTO			= 3014;
    public static long REQUEST_WINNING_LIST			= 3015;
    public static long REQUEST_JOIN_MEMBER			= 3016;
    public static long REQUEST_CURRENT_PASSWORD		= 3017;
    public static long REQUEST_POINT_COUPON_lIST 	= 3018;
    public static long REQUEST_POINT_STAR_lIST 		= 3019;
    public static long REQUEST_DAILY_INFO			= 3020;
    public static long REQUEST_DAILY_CHECK			= 3021;
    public static long REQUEST_UPLOAD_PHOTO			= 3022;
    public static long REQUEST_CHANGE_MYINFO		= 3023;
   
    private static final int MAX_IMAGE_DOWNLOAD_THREAD_COUNT = 3;
    
    private static MFNetworkManager m_sInstance = null;
    
    //////////////////////////////////////////////////////////////////////////////////////
    // normal property
    //////////////////////////////////////////////////////////////////////////////////////
    Context m_oContext         = null;
    private Handler m_oHandler = new Handler(Looper.getMainLooper());
    
    private ExecutorService m_oServerProcessor = null;//데이터 통신을 위한 Single-Thread Pool
    private ExecutorService m_oImageDownLoader = null;//이미지 다운로드를 위한 Multi-Thread Pool
    
    //////////////////////////////////////////////////////////////////////////////////////
    // interface
    //////////////////////////////////////////////////////////////////////////////////////
    public interface IOnNetworkListener
    {
        public void onNetMessage(int resultCode, NetMessage message);
    };
    
    //////////////////////////////////////////////////////////////////////////////////////
    // constructor
    //////////////////////////////////////////////////////////////////////////////////////
    private MFNetworkManager(Context context)
    {
        MFDebug.d(">> MFNetworkManager()");
        MFDebug.d("++ context : " + context);
        
        m_oServerProcessor = Executors.newSingleThreadExecutor();
        m_oImageDownLoader = Executors.newFixedThreadPool(MAX_IMAGE_DOWNLOAD_THREAD_COUNT);
        
        m_oContext = context;
    }
    
    //////////////////////////////////////////////////////////////////////////////////////
    // life cycle method
    //////////////////////////////////////////////////////////////////////////////////////
    public static MFNetworkManager getInstance(Context context)
    {
        MFDebug.d(">> getInstance()");
        MFDebug.d("++ context : " + context);
        
        if( m_sInstance == null ) {
            m_sInstance = new MFNetworkManager(context);
        }
        
        return m_sInstance;
    }
    
    public void release()
    {
        MFDebug.d(">> release()");
        
        if( m_oServerProcessor != null ) {
            try {
                m_oServerProcessor.shutdownNow();
                
            } catch (Exception e) {
                MFDebug.e(e);
            }
        }
        if( m_oImageDownLoader != null ) {
            try {
                m_oImageDownLoader.shutdownNow();
                
            } catch (Exception e) {
                MFDebug.e(e);
            }
        }
    }
    
    //////////////////////////////////////////////////////////////////////////////////////
    // public method
    //////////////////////////////////////////////////////////////////////////////////////
    
    public void requestImageData(long magicNum, String url, IOnNetworkListener listener)
    {
        MFDebug.d(">> requestImageData()");
        MFDebug.d("++ magicNum : " + magicNum);
        MFDebug.d("++ url : " + url);
        MFDebug.d("++ listener : " + listener);
        
        NetMessage message = new NetImage();
        message.setMagicNum(magicNum);
        message.setURL(url);
        message.setHttpMethod("GET");
        
        m_oImageDownLoader.execute(new NetTask(message, listener));
    }
    
    public void requestGetData(long magicNum, String url, IOnNetworkListener listener) {
    	MFDebug.d(">> requestDataByUrl()");
        MFDebug.d("++ url : " + url);
        MFDebug.d("++ listener : " + listener);
        
		NetMessage message = new NetJsonData();
		message.setMagicNum(magicNum);
		message.setURL(url);
		message.setHttpMethod("GET");
		
		m_oServerProcessor.execute(new NetTask(message, listener));
    }
    
    public void requestPostData(long magicNum, String url, Hashtable<String, String> param, IOnNetworkListener listener) {
    	MFDebug.d(">> requestDataByUrl()");
        MFDebug.d("++ url : " + url);
        MFDebug.d("++ param : " + param.toString());
        MFDebug.d("++ listener : " + listener);
        
		NetMessage message = new NetJsonData();
		message.setMagicNum(magicNum);
		message.setURL(url);
		message.setHttpMethod("POST");
		message.setParam(param);
		
		m_oServerProcessor.execute(new NetTask(message, listener));
    }
    
    public void requestUploadImage(long magicNum, String url, String strFilePath, String strFileName, IOnNetworkListener listener) {
    	MFDebug.d(">> requestDataByUrl()");
        MFDebug.d("++ url : " + url);
        MFDebug.d("++ listener : " + listener);
        
        NetUploadMessage message = new NetUploadMessage();
		message.setMagicNum(magicNum);
		message.setURL(url);
		message.setHttpMethod("POST");
		message.setFilePath(strFilePath);
		message.setFileName(strFileName);
		
		m_oServerProcessor.execute(new NetTask(message, listener));
    }
    
    public void requestBenfit(String param, IOnNetworkListener listener)
    {
    	MFDebug.d(">> requestBenfit()");
        MFDebug.d("++ param : " + param);
        MFDebug.d("++ listener : " + listener);
        
        NetMessage message = new NetJsonData();
        String Request_URL = UrlInfo.getBenefitURL() + "?mem_idx=" +param;
        message.setMagicNum(REQUEST_BENEFIT);
        message.setURL(Request_URL);
        message.setHttpMethod("GET");
        
        m_oServerProcessor.execute(new NetTask(message, listener));
    }
    
    public void requestBenfitDetail(String param, String param2, IOnNetworkListener listener)
    {
    	MFDebug.d(">> requestBenfit()");
        MFDebug.d("++ param : " + param);
        MFDebug.d("++ listener : " + listener);
        
        NetMessage message = new NetJsonData();
        String Request_URL = UrlInfo.getBenefitURL() + "?mem_idx=" +param + "&event_idx=" + param2;
        message.setMagicNum(REQUEST_BENEFIT_DETAIL);
        message.setURL(Request_URL);
        message.setHttpMethod("GET");
        
        m_oServerProcessor.execute(new NetTask(message, listener));
    }
    
    public void requestBenfitVote(String param1, String param2, String param3, IOnNetworkListener listener)
    {
    	MFDebug.d(">> requestBenfit()");
        MFDebug.d("++ param1 : " + param1);
        MFDebug.d("++ param2 : " + param2);
        MFDebug.d("++ param3 : " + param3);
        MFDebug.d("++ listener : " + listener);
        
        NetMessage message = new NetJsonData();
        String Request_URL = UrlInfo.getBenefitVoteURL();
        message.setMagicNum(REQUEST_BENEFIT_VOTE);
        message.setURL(Request_URL);
        message.setHttpMethod("POST");
        Hashtable<String, String> body = new Hashtable<String, String>();
        
        body.put("mem_idx", param1);
        body.put("event_idx", param2);
        body.put("num", param3);
        message.setParam(body);
        
        m_oServerProcessor.execute(new NetTask(message, listener));
    }
    
    public void requestBenfitResult(String param, IOnNetworkListener listener)
    {
    	MFDebug.d(">> requestBenfit()");
        MFDebug.d("++ param : " + param);
        MFDebug.d("++ listener : " + listener);
        
        NetMessage message = new NetJsonData();
        String Request_URL = UrlInfo.getBenefitResultURL() + "?mem_idx=" + param;
        message.setMagicNum(REQUEST_BENEFIT_RESULT);
        message.setURL(Request_URL);
        message.setHttpMethod("GET");
        
        m_oServerProcessor.execute(new NetTask(message, listener));
    }
    public void requestBenfitUser(String param,String param2, IOnNetworkListener listener)
    {
    	MFDebug.d(">> requestBenfit()");
        MFDebug.d("++ param : " + param);
        MFDebug.d("++ param2 : " + param2);
        MFDebug.d("++ listener : " + listener);
        
        NetMessage message = new NetJsonData();
        String Request_URL = UrlInfo.getBenefitUserURL() + "?mem_idx=" + param + "&event_idx="+ param2;
        message.setMagicNum(REQUEST_BENEFIT_USER);
        message.setURL(Request_URL);
        message.setHttpMethod("GET");
        
        m_oServerProcessor.execute(new NetTask(message, listener));
    }
    
    public void requestMain(IOnNetworkListener listener, String memIdx)
    {
    	String url = "http://api.wefansapp.com/lunchtime/get_ticket.php?"
    	           + "mem_idx="+memIdx;
    }
    
    /**
     * 투표하기(메인)의 Drawer 메뉴에 표시할 서버 데이터 연동
     * 
     * @param listener
     */
    public void requestGetUser(IOnNetworkListener listener)
    {
        MFDebug.d(">> requestGetUser()");
        MFDebug.d("++ listener : " + listener);
        
        final String url = UrlInfo.getUserInfo()
                         + "mem_idx=" + MFDataManager.getInstance(m_oContext).getMebmerIdx();
        
        MFDebug.i("++ url : " + url);
        
        NetMessage message = new NetJsonData();
        message.setMagicNum(REQUEST_GET_USER);
        message.setURL(url);
        message.setHttpMethod("GET");        
        
        m_oServerProcessor.execute(new NetTask(message, listener));
    }
    
    /**
     * 현재 진행중인 투표 리스트를 얻어온다.
     * 
     * @param listener
     */
    public void requestGetVote(IOnNetworkListener listener)
    {
        MFDebug.d(">> requestGetVote()");
        MFDebug.d("++ listener : " + listener);
        
        final String url = UrlInfo.getVote()
                         + "mem_idx=" + MFDataManager.getInstance(m_oContext).getMebmerIdx();

        MFDebug.i("++ url : " + url);
        
        NetMessage message = new NetJsonData();
        message.setMagicNum(REQUEST_GET_VOTE);
        message.setURL(url);
        message.setHttpMethod("GET");        
        
        m_oServerProcessor.execute(new NetTask(message, listener));
    }
    
    /**
     * 국가 정보를 가져온다.
     * 
     * @param listener
     */
    public void requestGetCountry(IOnNetworkListener listener)
    {
        MFDebug.d(">> requestGetCountry()");
        MFDebug.d("++ listener : " + listener);
        
        final String url = UrlInfo.getCountry();
        
        NetMessage message = new NetJsonData();
        message.setMagicNum(REQUEST_GET_COUNTRY);
        message.setURL(url);
        message.setHttpMethod("GET");    
        
        m_oServerProcessor.execute(new NetTask(message, listener));
    }
    
    /**
     * 앱 업데이트 여부 및 버전 정보를 가져온다.
     * 
     * @param listener
     */
    public void requestGetAppVer(IOnNetworkListener listener)
    {
        MFDebug.d(">> requestGetAppVer()");
        MFDebug.d("++ listener : " + listener);
        
        final String url = UrlInfo.getAppVer()
                         + "app_ver" + "=" + FEATURES.APP_VERSION;
        
        NetMessage message = new NetJsonData();
        message.setMagicNum(REQUEST_GET_APP_VERSION);
        message.setURL(url);
        message.setHttpMethod("GET");    
        
        m_oServerProcessor.execute(new NetTask(message, listener));
    }
    
    /**
     * 투표하기 상세 정보 가져오기
     * 
     * @param listener
     * @param pollIdx
     * @param cateIdx
     */
    public void requestGetVoteOne(IOnNetworkListener listener, String pollIdx, String cateIdx)
    {
        MFDebug.d(">> requestGetVoteOne()");
        MFDebug.d("++ listener : " + listener);
        MFDebug.d("++ pollIdx : " + pollIdx);
        MFDebug.d("++ cateIdx : " + cateIdx);
        
        final String url = UrlInfo.getVoteOne()
                         + "mem_idx"  + "=" + MFDataManager.getInstance(m_oContext).getMebmerIdx()
                         + "&poll_idx" + "=" + pollIdx
                         + "&cate_idx" + "=" + cateIdx;
        
        NetMessage message = new NetJsonData();
        message.setMagicNum(REQUEST_GET_VOTE_ONE);
        message.setURL(url);
        message.setHttpMethod("GET");    
        
        m_oServerProcessor.execute(new NetTask(message, listener));
    }
    
    /**
     * 투표를 진행한다.
     * 
     * @param listener
     * @param mem_idx
     * @param chart_idx
     * @param cate_idx
     * @param question_idx
     * @param num
     * @param app_version
     * @param device_type
     */
    public void requestSetVote(IOnNetworkListener listener, String mem_idx, String chart_idx, String cate_idx
            , String question_idx, String num, String app_version, String device_type)
    {
        MFDebug.d(">> requestGetVoteOne()");
        MFDebug.d("++ listener : " + listener);
        MFDebug.d("++ mem_idx : " + mem_idx);
        MFDebug.d("++ chart_idx : " + chart_idx);
        MFDebug.d("++ cate_idx : " + cate_idx);
        MFDebug.d("++ question_idx : " + question_idx);
        MFDebug.d("++ num : " + num);
        MFDebug.d("++ app_version : " + app_version);
        MFDebug.d("++ device_type : " + device_type);
        
        final String url = UrlInfo.setVote();
        
        NetMessage message = new NetJsonData();
        message.setMagicNum(REQUEST_SET_VOTE);
        message.setURL(url);
        message.setHttpMethod("POST");
        
        Hashtable<String, String> params = new Hashtable<String, String>();
        params.put("mem_idx", mem_idx);
        params.put("chart_idx", chart_idx);
        params.put("cate_idx", cate_idx);
        params.put("question_idx", question_idx);
        params.put("num", num);
        params.put("app_version", app_version);
        params.put("device_type", device_type);
        
        message.setParam(params);
        
        m_oServerProcessor.execute(new NetTask(message, listener));
    }
    
    public void requestReplayList(IOnNetworkListener listener, 
    							  String replyType, 
    							  String parentIdx, 
    							  String commentIdx, 
    							  String page, 
    							  String orderby)
    {
        MFDebug.d(">> requestReplayList()");
        MFDebug.d("++ replyType : " + replyType);
        MFDebug.d("++ parentIdx : " + parentIdx);
        MFDebug.d("++ commentIdx : " + commentIdx);
        MFDebug.d("++ page : " + page);
        MFDebug.d("++ orderby : " + orderby);
        
        final String url = UrlInfo.getReplyList()
                         + "mem_idx"  + "=" + MFDataManager.getInstance(m_oContext).getMebmerIdx()
                         + "&board_type" + "=" + replyType
                         + "&parent_idx" + "=" + parentIdx
                         + "&comment_idx" + "=" + parentIdx
                         + "&page" + "=" + page
                         + "&orderby" + "=" + orderby;
        
        NetMessage message = new NetJsonData();
        message.setMagicNum(REQUEST_REPLY_LIST);
        message.setURL(url);
        message.setHttpMethod("GET");    
        
        m_oServerProcessor.execute(new NetTask(message, listener));
    }
    
    public void requestReplayRegist(IOnNetworkListener listener, 
									  String boardType, 
									  String parentIdx, 
									  String parentCommentIdx, 
									  String comment) {
    	MFDebug.d(">> requestReplayRegist()");
        MFDebug.d("++ boardType : " + boardType);
        MFDebug.d("++ parentIdx : " + parentIdx);
        MFDebug.d("++ parent_comment_idx : " + parentCommentIdx);
        MFDebug.d("++ comment : " + comment);
        
        final String url = UrlInfo.getReplyList() + UrlInfo.registReply();                         
        
        NetMessage message = new NetJsonData();
        message.setMagicNum(REQUEST_REPLY_REGIST);
        message.setURL(url);
        message.setHttpMethod("POST");
        
        Hashtable<String, String> body = new Hashtable<String, String>();
        
        body.put("mem_idx", MFDataManager.getInstance(m_oContext).getMebmerIdx());
        body.put("board_type", boardType);
        body.put("parent_idx", (parentIdx == null) ? "" : parentIdx);
        body.put("parent_comment_idx", parentCommentIdx);
        body.put("comment", comment);
        message.setParam(body);
        
        m_oServerProcessor.execute(new NetTask(message, listener));
    }
    
    public void requestReplayDel(IOnNetworkListener listener, 
			  String replyType, 
			  String parentIdx, 
			  String commentIdx, 
			  String page, 
			  String orderby) {
  	MFDebug.d(">> requestReplayList()");
      MFDebug.d("++ replyType : " + replyType);
      
      final String url = UrlInfo.getReplyList()
                       + "mem_idx"  + "=" + MFDataManager.getInstance(m_oContext).getMebmerIdx()
                       + "&page" + "=" + page
                       + "&orderby" + "=" + orderby;
      
      NetMessage message = new NetJsonData();
      message.setMagicNum(REQUEST_REPLY_DEL);
      message.setURL(url);
      message.setHttpMethod("GET");    
      
      m_oServerProcessor.execute(new NetTask(message, listener));
  }
    
    public void requestReplayReport(IOnNetworkListener listener, 
			  String replyType, 
			  String parentIdx, 
			  String commentIdx, 
			  String page, 
			  String orderby) {
	MFDebug.d(">> requestReplayList()");
    MFDebug.d("++ replyType : " + replyType);
    
    final String url = UrlInfo.getReplyList()
                     + "mem_idx"  + "=" + MFDataManager.getInstance(m_oContext).getMebmerIdx()
                     + "&page" + "=" + page
                     + "&orderby" + "=" + orderby;
    
    NetMessage message = new NetJsonData();
    message.setMagicNum(REQUEST_REPLY_REPORT);
    message.setURL(url);
    message.setHttpMethod("GET");    
    
    m_oServerProcessor.execute(new NetTask(message, listener));
}
    
    //////////////////////////////////////////////////////////////////////////////////////
    // private method
    //////////////////////////////////////////////////////////////////////////////////////
    
    class NetTask implements Runnable
    {
        private NetMessage         m_oNetMsg     = null;
        private IOnNetworkListener m_onListener  = null;
        
        public NetTask(NetMessage request, IOnNetworkListener listener)
        {
            m_oNetMsg    = request;
            m_onListener = listener;
        }
        
        public void sendOnNetMessage(final int resultCode, final NetMessage message)
        {
            if( m_onListener != null ) {
                m_oHandler.post(new Runnable()
                {
                    @Override
                    public void run()
                    {
                        m_onListener.onNetMessage(resultCode, message);
                    }
                });
            }
        }
        
        @Override
        public void run()
        {
            int resultCode = 0;
            
            try {
                if( m_oNetMsg == null ) {
                    throw new IllegalArgumentException("There are NO request message.");
                }
                if( m_oNetMsg.getURL() == null ) {
                    throw new IllegalArgumentException("There are NO request url.");
                }
                
                //image download
                if( m_oNetMsg instanceof NetImage ) {
                    byte[] buffer = MFNetwork.getServerData(m_oNetMsg.getURL(), m_oNetMsg.getHttpMethod(), m_oNetMsg.getParam());
                    if( buffer == null || buffer.length < 1 ) {
                        throw new RuntimeException("There are No response data.");
                    }
                    
                    ((NetImage)m_oNetMsg).setResponseBinary(buffer);
                    
                }
                //data download
                else if ( m_oNetMsg instanceof NetUploadMessage) {
                	byte[] buffer = MFNetwork.uploadFile(m_oNetMsg.getURL(), ((NetUploadMessage) m_oNetMsg).getFilePath(), ((NetUploadMessage) m_oNetMsg).getFileName());
                    if( buffer == null || buffer.length < 1 ) {
                        throw new RuntimeException("There are No response data.");
                    }
                    
                    String json = new String(buffer);
                    MFDebug.i("+++++++++++++++++++++++++++++++++++++++++++++++++");
                    MFDebug.i("[Server Data]");
                    MFDebug.i("++ json : \n" + json);
                    MFDebug.i("+++++++++++++++++++++++++++++++++++++++++++++++++");
                    
                    ((NetUploadMessage)m_oNetMsg).setResponseJson(json);
                    
                } else {
                
                    byte[] buffer = MFNetwork.getServerData(m_oNetMsg.getURL(), m_oNetMsg.getHttpMethod(), m_oNetMsg.getParam());
                    if( buffer == null || buffer.length < 1 ) {
                        throw new RuntimeException("There are No response data.");
                    }
                    
                    String json = new String(buffer);
                    MFDebug.i("+++++++++++++++++++++++++++++++++++++++++++++++++");
                    MFDebug.i("[Server Data]");
                    MFDebug.i("++ json : \n" + json);
                    MFDebug.i("+++++++++++++++++++++++++++++++++++++++++++++++++");
                    
                    ((NetJsonData)m_oNetMsg).setResponseJson(json);
                }
                
            } catch (Exception e) {
                MFDebug.e(e);
                resultCode = -1;
                
            } finally {
                sendOnNetMessage(resultCode, m_oNetMsg);
                
            }
        }//runnable
    };//end of inner class
}
